/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/math/vector/FPU
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AESimdFloat32_Fpu.inl
// Author:		Gianluca Belardelli
// Date:		17/01/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AESIMDFLOAT32_FPU_INL_
#define _AESIMDFLOAT32_FPU_INL_

/*
template<int vectorConstant>
HK_FORCE_INLINE const AESimdFloat32 HK_CALL AESimdFloat32::getConstant()
{
	HK_COMPILE_TIME_ASSERT2( 
		(vectorConstant!=HK_QUADREAL_1000) && (vectorConstant!=HK_QUADREAL_0100) && (vectorConstant!=HK_QUADREAL_0010) && (vectorConstant!=HK_QUADREAL_0001) &&
		(vectorConstant!=HK_QUADREAL_m11m11) && (vectorConstant!=HK_QUADREAL_1248) && (vectorConstant!=HK_QUADREAL_8421) && (vectorConstant!=HK_QUADREAL_1010)  && (vectorConstant!=HK_QUADREAL_1100)
		, HK_SIMDFLOAT_ILLEGAL_CONSTANT_REQUEST);
#if !defined(HK_PLATFORM_RVL) && !defined(HK_PLATFORM_WIIU)
	return Convert((g_vectorfConstants + vectorConstant)->v[0]);
#else
	return *(const AESimdFloat32*) (g_vectorfConstants + vectorConstant);
#endif
}

HK_FORCE_INLINE const AESimdFloat32 HK_CALL AESimdFloat32::getConstant(hkVectorConstant constant)
{	
	HK_MATH_ASSERT( 0x909ff234,
		(constant!=HK_QUADREAL_1000) && (constant!=HK_QUADREAL_0100) && (constant!=HK_QUADREAL_0010) && (constant!=HK_QUADREAL_0001) &&
		(constant!=HK_QUADREAL_m11m11) && (constant!=HK_QUADREAL_1248) && (constant!=HK_QUADREAL_8421) && (constant!=HK_QUADREAL_1010)  && (constant!=HK_QUADREAL_1100)
		, "not a simdreal constant");
#if !defined(HK_PLATFORM_RVL) && !defined(HK_PLATFORM_WIIU)
	return Convert((g_vectorfConstants + constant)->v[0]);
#else
	return *(const AESimdFloat32*) (g_vectorfConstants + constant);
#endif
}
*/

AE_FORCEINLINE AESimdFloat32::AESimdFloat32(const AEFLOAT32 &fValue )
{
	m_fReal = fValue;
}

AE_FORCEINLINE AESimdFloat32::operator AEFLOAT32() const
{
	return m_fReal;
}

AE_FORCEINLINE AEFLOAT32 AESimdFloat32::GetReal( void ) const
{
	return m_fReal;
}

AE_FORCEINLINE void AESimdFloat32::SetFromFloat( const AEFLOAT32 &fValue )
{
	m_fReal = AEFLOAT32( fValue );
}

AE_FORCEINLINE void AESimdFloat32::SetFromFloat( const AEDOUBLE64 &dValue )
{
	m_fReal = AEFLOAT32( dValue );
}

AE_FORCEINLINE void AESimdFloat32::SetFromInt32( const AEINT32 &nValue )
{
	m_fReal = AEFLOAT32( nValue );
}

AE_FORCEINLINE void AESimdFloat32::SetFromUint16( const AEUINT16 &uiValue )
{
	int i = uiValue;
	SetFromInt32(i);
}

AE_FORCEINLINE void AESimdFloat32::SetFromUint8( const AEUINT8 &uiValue )
{
	int i = uiValue;
	SetFromInt32( uiValue );
}

AE_FORCEINLINE void AESimdFloat32::SetZero( void )
{
	m_fReal = AEFLOAT32(0);
}

AE_FORCEINLINE void AESimdFloat32::StoreSaturateInt32( AEINT32 *lpRes ) const
{
	*lpRes = int( m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::StoreSaturateUint16( AEUINT16 *lpRes ) const
{
	const AEINT32 i = int( m_fReal );
	const AEINT32 clampPos    = AEMath::Max<AEINT32>( i, 0x0 );
	const AEINT32 clampPosNeg = AEMath::Min<AEINT32>( clampPos, 0xffff );
	*lpRes = AEUINT16( clampPosNeg );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::operator+ ( AESimdFloat32ConstRef fParam ) const
{
	return AESimdFloat32::Convert( m_fReal + fParam.m_fReal );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::operator- ( AESimdFloat32ConstRef fParam ) const
{
	return AESimdFloat32::Convert( m_fReal - fParam.m_fReal );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::operator* ( AESimdFloat32ConstRef fParam ) const
{
	return AESimdFloat32::Convert( m_fReal * fParam.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator< ( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal < fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator<= ( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal <= fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator> ( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal > fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator>= ( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal >= fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator== ( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal == fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator!= ( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal != fValue.m_fReal );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::operator-( void ) const
{
	return AESimdFloat32::Convert( -m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetMin( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	m_fReal = AEMath::Min<AESingleFloat32>( fParam1.m_fReal, fParam2.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetMax( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	m_fReal = AEMath::Max<AESingleFloat32>( fParam1.m_fReal, fParam2.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetAbs( AESimdFloat32ConstRef fParam )
{
	m_fReal = AEMath::Abs( fParam.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetFloor( AESimdFloat32ConstRef fParam )
{
	m_fReal = AEMath::Floor( fParam.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetMod( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	m_fReal = AEMath::Mod( fParam1.m_fReal, fParam2.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetFlipSign( AESimdFloat32ConstRef fParam, AESimdFloat32ConstRef fSign )
{
	m_fReal = AEMath::HasSignBitSet( fSign.m_fReal ) ? -fParam.m_fReal : fParam.m_fReal;
}

AE_FORCEINLINE void AESimdFloat32::SetSelect( AEVector4fConstRefCompParam vcComp, AESimdFloat32ConstRef fTrueValue, AESimdFloat32ConstRef fFalseValue  )
{
	AEASSERT_MSG( vcComp.AllAreSet() || ( vcComp.GetMask() == AEVector4ComparisonMask::MASK_NONE), "illegal compare mask");
	m_fReal = vcComp.m_mMask ? fTrueValue.m_fReal : fFalseValue.m_fReal;
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsSignBitSet( void ) const
{
	return AEMath::SignBitSet( m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsSignBitClear( void ) const
{
	return !AEMath::SignBitSet( m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsLess( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal < fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsLessEqual( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal <= fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsGreater( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal > fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsGreaterEqual( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal >= fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsEqual( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal == fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsNotEqual( AESimdFloat32ConstRef fValue ) const
{
	return ( m_fReal != fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsLessZero( void ) const
{
	return ( m_fReal < AEFLOAT32(0) );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsLessEqualZero( void ) const
{
	return ( m_fReal <= AEFLOAT32(0) );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsGreaterZero( void ) const
{
	return ( m_fReal > AEFLOAT32(0) );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsGreaterEqualZero( void ) const
{
	return ( m_fReal >= AEFLOAT32(0) );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsEqualZero( void ) const
{
	return ( m_fReal == AEFLOAT32(0) );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsNotEqualZero( void ) const
{
	return ( m_fReal != AEFLOAT32(0) );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsOk( void ) const
{
	return AEMath::IsFiniteNumber( m_fReal );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpL( AESimdFloat32ConstRef fValue ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal < fValue.m_fReal ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpLE( AESimdFloat32ConstRef fValue ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal <= fValue.m_fReal ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpG( AESimdFloat32ConstRef fValue ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal > fValue.m_fReal ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpGE( AESimdFloat32ConstRef fValue ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal >= fValue.m_fReal ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpE( AESimdFloat32ConstRef fValue ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal == fValue.m_fReal ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpNE( AESimdFloat32ConstRef fValue ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal != fValue.m_fReal ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpLessZero( void ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal < AEFLOAT32(0) ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpLessEqualZero( void ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal <= AEFLOAT32(0) ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpGreaterZero( void ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal > AEFLOAT32(0) ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpGreaterEqualZero( void ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal >= AEFLOAT32(0) ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpEqualZero( void ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal == AEFLOAT32(0) ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpNotEqualZero( void ) const
{
	AEVector4fComparison res;
	res.m_mMask = ( m_fReal != AEFLOAT32(0) ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return res;
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathIoMode A>
	struct unrollf_load
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};
	
	template <AEMathIoMode A>
	struct unrollf_load_D
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};
	
	template <>
	struct unrollf_load<AE_IO_BYTE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			fSelf = AEFLOAT32( lpAddr[0] );
		}
	};
	
	template <>
	struct unrollf_load_D<AE_IO_BYTE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			fSelf = AEFLOAT32( lpAddr[0] );
		}
	};
	
	template <>
	struct unrollf_load<AE_IO_NATIVE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			AEASSERT_MSG( ( ((AEUINT32)lpAddr) & (sizeof(AEFLOAT32)-1) ) == 0, "pointer must be aligned to native size of AEFLOAT32.");
			fSelf = AEFLOAT32( lpAddr[0] );
		}
	};
	
	template <>
	struct unrollf_load_D<AE_IO_NATIVE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			AEASSERT_MSG( ( ((AEUINT32)lpAddr) & (sizeof(AEDOUBLE64)-1) ) == 0, "pointer must be aligned to native size of AEDOUBLE64.");
			fSelf = AEFLOAT32( lpAddr[0] );
		}
	};
	
	template <>
	struct unrollf_load<AE_IO_SIMD_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			unrollf_load<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
	
	template <>
	struct unrollf_load_D<AE_IO_SIMD_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			unrollf_load_D<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
	
	template <>
	struct unrollf_load<AE_IO_NOT_CACHED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			unrollf_load<AE_IO_SIMD_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
	
	template <>
	struct unrollf_load_D<AE_IO_NOT_CACHED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			unrollf_load_D<AE_IO_SIMD_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
} // namespace 

template <int N, AEMathIoMode A>
AE_FORCEINLINE void AESimdFloat32::Load( const AEFLOAT32 *lpAddr )
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_load<A>::Apply( m_fReal, lpAddr );
}

template <int N, AEMathIoMode A>
AE_FORCEINLINE void AESimdFloat32::Load( const AEDOUBLE64 *lpAddr )
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_load_D<A>::Apply( m_fReal, lpAddr );
}

template <int N>
AE_FORCEINLINE void AESimdFloat32::Load( const AEFLOAT32 *lpAddr )
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_load<AE_IO_SIMD_ALIGNED>::Apply( m_fReal, lpAddr );
}

template <int N>
AE_FORCEINLINE void AESimdFloat32::Load( const AEDOUBLE64 *lpAddr )
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_load_D<AE_IO_SIMD_ALIGNED>::Apply( m_fReal, lpAddr );
}

AE_FORCEINLINE void AESimdFloat32::ZeroIfFalse( AEVector4fConstRefCompParam vcCompareMask )
{
	AEASSERT_MSG( vcCompareMask.AllAreSet() || ( vcCompareMask.GetMask() == AEVector4ComparisonMask::MASK_NONE ), "illegal compare mask" );
	m_fReal = vcCompareMask.m_mMask ? m_fReal : AEFLOAT32(0);
}

AE_FORCEINLINE void AESimdFloat32::ZeroIfTrue( AEVector4fConstRefCompParam vcCompareMask )
{
	AEASSERT_MSG( vcCompareMask.AllAreSet() || ( vcCompareMask.GetMask() == AEVector4ComparisonMask::MASK_NONE ), "illegal compare mask" );
	m_fReal = vcCompareMask.m_mMask ? AEFLOAT32(0) : m_fReal;
}

AE_FORCEINLINE void AESimdFloat32::SetFlipSign( AESimdFloat32ConstRef fParam, AEVector4fConstRefCompParam vcMask )
{
	AEASSERT_MSG( vcMask.AllAreSet() || ( vcMask.GetMask() == AEVector4ComparisonMask::MASK_NONE ), "illegal compare mask" );
	m_fReal = vcMask.m_mMask ? -fParam.m_fReal : fParam.m_fReal;
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathIoMode A>
	struct unrollf_store
	{ 
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};

	template <AEMathIoMode A>
	struct unrollf_store_D
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};

	template <>
	struct unrollf_store<AE_IO_BYTE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			lpAddr[0] = AEFLOAT32( fSelf );
		}
	};

	template <>
	struct unrollf_store_D<AE_IO_BYTE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			lpAddr[0] = AEDOUBLE64( fSelf );
		}
	};

	template <>
	struct unrollf_store<AE_IO_NATIVE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			AEASSERT_MSG( ( ((AEUINT32)lpAddr) & (sizeof(AEFLOAT32)-1) ) == 0, "pointer must be aligned to native size of AEFLOAT32.");
			lpAddr[0] = AEFLOAT32( fSelf );
		}
	};

	template <>
	struct unrollf_store_D<AE_IO_NATIVE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			AEASSERT_MSG( ( ((AEUINT32)lpAddr) & (sizeof(AEDOUBLE64)-1) ) == 0, "pointer must be aligned to native size of AEDOUBLE64.");
			lpAddr[0] = AEDOUBLE64( fSelf );
		}
	};

	template <>
	struct unrollf_store<AE_IO_SIMD_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			unrollf_store<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};

	template <>
	struct unrollf_store_D<AE_IO_SIMD_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			unrollf_store_D<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};

	template <>
	struct unrollf_store<AE_IO_NOT_CACHED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			unrollf_store<AE_IO_SIMD_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};

	template <>
	struct unrollf_store_D<AE_IO_NOT_CACHED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			unrollf_store_D<AE_IO_SIMD_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
} // namespace 

template <int N, AEMathIoMode A, AEMathRoundingMode R>
AE_FORCEINLINE void AESimdFloat32::Store( AEFLOAT32 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store<A>::Apply( m_fReal, lpAddr );
}

template <int N, AEMathIoMode A, AEMathRoundingMode R>
AE_FORCEINLINE void AESimdFloat32::Store( AEDOUBLE64 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store_D<A>::Apply( m_fReal, lpAddr );
}

template <int N, AEMathIoMode A>
AE_FORCEINLINE void AESimdFloat32::Store( AEFLOAT32 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store<A>::Apply( m_fReal, lpAddr );
}

template <int N, AEMathIoMode A>
AE_FORCEINLINE void AESimdFloat32::Store( AEDOUBLE64 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store_D<A>::Apply( m_fReal, lpAddr );
}

template <int N>
AE_FORCEINLINE void AESimdFloat32::Store( AEFLOAT32 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store<AE_IO_SIMD_ALIGNED>::Apply( m_fReal, lpAddr );
}

template <int N>
AE_FORCEINLINE void AESimdFloat32::Store( AEDOUBLE64 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store_D<AE_IO_SIMD_ALIGNED>::Apply( m_fReal, lpAddr );
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D>
	struct unrollf_setDiv
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_IGNORE>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			switch (A)
			{
				case AE_ACC_23_BIT: { AEFLOAT32 x = AEMath::RcpF32Approx23Bit( AEFLOAT32( fParam2.m_fReal ) ); fSelf = fParam1.m_fReal * AEFLOAT32(x); } break;
				case AE_ACC_12_BIT: { AEFLOAT32 x = AEMath::RcpF32Approx12Bit( AEFLOAT32( fParam2.m_fReal ) ); fSelf = fParam1.m_fReal * AEFLOAT32(x); } break;
				default:			fSelf = fParam1.m_fReal / fParam2.m_fReal; break;
			}
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_SET_ZERO>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			if( fParam2.m_fReal == AEFLOAT32(0) )
			{
				fSelf = AEFLOAT32(0);
				return;
			}
			
			unrollf_setDiv<A, AE_DIV_IGNORE>::Apply( fSelf, fParam1, fParam2 );
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_SET_HIGH>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			if( fParam2.m_fReal == AEFLOAT32(0) )
			{
				fSelf = ( fParam1.m_fReal < 0 ) ? -AE_FLOAT_HIGH : AE_FLOAT_HIGH;
				return;
			}
			
			unrollf_setDiv<A, AE_DIV_IGNORE>::Apply( fSelf, fParam1, fParam2 );
		}
	};

	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_SET_MAX>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			if( fParam2.m_fReal == AEFLOAT32(0) )
			{
				fSelf = ( fParam1.m_fReal < 0 ) ? -AE_FLOAT_MAX : AE_FLOAT_MAX;
				return;
			}
			
			unrollf_setDiv<A, AE_DIV_IGNORE>::Apply( fSelf, fParam1, fParam2 );
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_SET_ZERO_AND_ONE>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			unrollf_setDiv<A, AE_DIV_SET_ZERO>::Apply( fSelf, fParam1, fParam2 );
			const AESingleFloat32 absValLessOne = AEMath::Abs( fSelf - AEFLOAT32(1) );
			if( absValLessOne <= AEMATH_EPSILON )
				fSelf = AEFLOAT32(1);
		}
	};
} // End namespace 

template <AEMathAccuracyMode A, AEMathDivByZeroMode D> 
AE_FORCEINLINE void AESimdFloat32::SetDiv( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	AESimdReal_AdvancedInterface::unrollf_setDiv<A,D>::Apply( m_fReal, fParam1, fParam2 );
}

AE_FORCEINLINE void AESimdFloat32::SetDiv( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	AESimdReal_AdvancedInterface::unrollf_setDiv<AE_ACC_23_BIT,AE_DIV_IGNORE>::Apply( m_fReal, fParam1, fParam2 );
}

template <AEMathAccuracyMode A, AEMathDivByZeroMode D> 
AE_FORCEINLINE void AESimdFloat32::Div( AESimdFloat32ConstRef fParam )
{
	SetDiv<A,D>( *this, fParam );
}

AE_FORCEINLINE void AESimdFloat32::Div( AESimdFloat32ConstRef fParam )
{
	SetDiv( *this, fParam );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::SignBitSet( void ) const
{
	AEVector4fComparison vcCompRes;
	vcCompRes.m_mMask = AEMath::SignBitSet( m_fReal ) ? AEVector4ComparisonMask::MASK_XYZW : AEVector4ComparisonMask::MASK_NONE;
	return vcCompRes;
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::SignBitClear( void ) const
{
	AEVector4fComparison vcCompRes;
	vcCompRes.m_mMask = AEMath::SignBitSet( m_fReal ) ? AEVector4ComparisonMask::MASK_NONE : AEVector4ComparisonMask::MASK_XYZW;
	return vcCompRes;
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathAccuracyMode A, AEMathNegSqrtMode S>
	struct unrollf_sqrt
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
			return AEFLOAT32(0);
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_sqrt<A, AE_SQRT_IGNORE>
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			switch (A)
			{
				case AE_ACC_23_BIT: return AEFLOAT32( AEFLOAT32( fSelf.m_fReal ) * AEMath::InvSqrtF32Approx23Bit( AEFLOAT32( fSelf.m_fReal ) ) ); break;
				case AE_ACC_12_BIT: return AEFLOAT32( AEFLOAT32( fSelf.m_fReal ) * AEMath::InvSqrtF32Approx12Bit( AEFLOAT32( fSelf.m_fReal ) ) ); break;
				default:            return AEMath::Sqrt( fSelf.m_fReal ); break;
			}
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_sqrt<A, AE_SQRT_SET_ZERO>
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			if( fSelf.m_fReal <= AEFLOAT32(0) )
				return AEFLOAT32(0);

			return unrollf_sqrt<A, AE_SQRT_IGNORE>::Apply( fSelf );
		}
	};
} // End namespace 

template <AEMathAccuracyMode A, AEMathNegSqrtMode S> 
AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::Sqrt( void ) const
{
	return AESimdFloat32::Convert( AESimdReal_AdvancedInterface::unrollf_sqrt<A,S>::Apply( *this ) );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::Sqrt( void ) const
{
	return AESimdFloat32::Convert( AESimdReal_AdvancedInterface::unrollf_sqrt<AE_ACC_23_BIT,AE_SQRT_SET_ZERO>::Apply( *this ) );
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathAccuracyMode A, AEMathNegSqrtMode S>
	struct unrollf_sqrtInverse
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
			return AEFLOAT32(0);
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_sqrtInverse<A, AE_SQRT_IGNORE>
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			switch (A)
			{
				case AE_ACC_23_BIT: return AEFLOAT32( AEMath::InvSqrtF32Approx23Bit( AEFLOAT32( fSelf.m_fReal ) ) ); break;
				case AE_ACC_12_BIT: return AEFLOAT32( AEMath::InvSqrtF32Approx12Bit( AEFLOAT32( fSelf.m_fReal ) ) ); break;
				default:			return AEMath::SqrtInverse( fSelf.m_fReal ); break;
			}
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_sqrtInverse<A, AE_SQRT_SET_ZERO>
	{
		AE_FORCEINLINE static AESingleFloat32 Apply(AESimdFloat32ConstRef fSelf )
		{
			if( fSelf.m_fReal <= AEFLOAT32(0) )
				return AEFLOAT32(0);

			return unrollf_sqrtInverse<A, AE_SQRT_IGNORE>::Apply( fSelf );
		}
	};
} // End namespace 

template <AEMathAccuracyMode A, AEMathNegSqrtMode S> 
AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::SqrtInverse( void ) const
{
	return AESimdFloat32::Convert( AESimdReal_AdvancedInterface::unrollf_sqrtInverse<A,S>::Apply( *this ) );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::SqrtInverse( void ) const
{
	return AESimdFloat32::Convert(AESimdReal_AdvancedInterface::unrollf_sqrtInverse<AE_ACC_23_BIT, AE_SQRT_SET_ZERO>::Apply( *this ) );
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D>
	struct unrollf_setReciprocal
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_IGNORE>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			switch (A)
			{
				case AE_ACC_23_BIT: { AEFLOAT32 x = AEMath::RcpF32Approx23Bit( AEFLOAT32( fValue.m_fReal ) ); fSelf = AEFLOAT32(x); } break;
				case AE_ACC_12_BIT: { AEFLOAT32 x = AEMath::RcpF32Approx12Bit( AEFLOAT32( fValue.m_fReal ) ); fSelf = AEFLOAT32(x); } break;
				default:            fSelf = AEFLOAT32(1) / fValue.m_fReal; break;
			}
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_SET_ZERO>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			if( fValue.m_fReal == AEFLOAT32(0) )
			{
				fSelf = AEFLOAT32(0);
				return;
			}
			
			unrollf_setReciprocal<A, AE_DIV_IGNORE>::Apply( fSelf, fValue );
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_SET_HIGH>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			if( fValue.m_fReal == AEFLOAT32(0) )
			{
				fSelf = AE_FLOAT_HIGH;
				return;
			}
			
			unrollf_setReciprocal<A, AE_DIV_IGNORE>::Apply( fSelf, fValue );
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_SET_MAX>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			if( fValue.m_fReal == AEFLOAT32(0) )
			{
				fSelf = AE_FLOAT_MAX;
				return;
			}
			
			unrollf_setReciprocal<A, AE_DIV_IGNORE>::Apply( fSelf, fValue );
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_SET_ZERO_AND_ONE>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			unrollf_setReciprocal<A, AE_DIV_SET_ZERO>::Apply( fSelf, fValue );
			const AESingleFloat32 absValLessOne = AEMath::Abs( fSelf - AEFLOAT32(1) );
			if( absValLessOne <= AEMATH_EPSILON )
				fSelf = AEFLOAT32(1);
		}
	};
} // End namespace 

template <AEMathAccuracyMode A, AEMathDivByZeroMode D> 
AE_FORCEINLINE void AESimdFloat32::SetReciprocal( AESimdFloat32ConstRef fValue )
{
	AESimdReal_AdvancedInterface::unrollf_setReciprocal<A,D>::Apply( m_fReal, fValue );
}

AE_FORCEINLINE void AESimdFloat32::SetReciprocal( AESimdFloat32ConstRef fValue )
{
	AESimdReal_AdvancedInterface::unrollf_setReciprocal<AE_ACC_23_BIT,AE_DIV_IGNORE>::Apply( m_fReal, fValue );
}

#endif // _AESIMDFLOAT32_FPU_INL_
